package com.czk.model.singleton;

import java.io.Serializable;
import java.util.concurrent.atomic.AtomicReference;

// 饿汉式第一种 鼎泰变量式，可能会造成内存的浪费
public class SingletonTest01 {
    //构造器私有化
    private SingletonTest01() {
    }

    ;
    //提供静态方法
    private static SingletonTest01 singletonTest01 = new SingletonTest01();

    //获取对象的静态方法
    public static SingletonTest01 getInstance() {
        return singletonTest01;
    }

    public static void main(String[] args) {
        SingletonTest01 instance = SingletonTest01.getInstance();
        SingletonTest01 instance1 = SingletonTest01.getInstance();
        System.out.println(instance.equals(instance1));
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

// 静态代码块的方式
class SingletonTest02 {
    private SingletonTest02() {
    }

    ;
    private static SingletonTest02 singletonTest02;

    static {
        singletonTest02 = new SingletonTest02();
    }

    public static SingletonTest02 getInstance() {
        return singletonTest02;
    }

    public static void main(String[] args) {
        SingletonTest02 instance = SingletonTest02.getInstance();
        SingletonTest02 instance1 = SingletonTest02.getInstance();
        System.out.println(instance.equals(instance1));
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

//懒汉式，线程不安全
class SingletonTest03 {
    private SingletonTest03() {
    }

    ;
    public static SingletonTest03 singletonTest03;

    //第一次为空时创建
    public static SingletonTest03 getInstance() {
        if (singletonTest03 == null) {
            // 线程一到这儿时，被线程二抢占，此时会造成线程不安全的问题
            singletonTest03 = new SingletonTest03();
        }
        return singletonTest03;
    }

    public static void main(String[] args) {
        SingletonTest03 instance = SingletonTest03.getInstance();
        SingletonTest03 instance1 = SingletonTest03.getInstance();
        System.out.println(instance.equals(instance1));
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}

// 懒汉式，线程安全问题 缺点：效率比较低 实际上不推荐使用
class SingletonTest04 {
    private SingletonTest04() {
    }

    ;
    private static SingletonTest04 singletonTest04;

    // 加入同步代码块，防止线程安全问题
    public static synchronized SingletonTest04 getInstance() {
        if (singletonTest04 == null) {
            singletonTest04 = new SingletonTest04();
        }
        return singletonTest04;
    }
}
//懒汉式 双重检查

/**
 * 二、为什么需要加volatile才可以？
 * <p>
 * 因为：
 * 1、先说下new Object()在底层是几步骤
 * <p>
 * 1.memory=allocate()分配对象的内存空间。
 * 2.createInstance()初始化对象
 * 3.instance=memory 设置instance指向刚分配的内存
 * <p>
 * 2、再说下为什么需要volatile
 * 因为JVM指令重排序。
 * 若3.和2.被重排序换位置了，那结果是先分配内存空间，然后指向，最后初始化对象。那么我们这时候虽然是有synchronize，但是两次进入都发现没有初始化对象，因为他指向内存分配的空间了，尚未初始化对象。
 */
class SingletonTest05 implements Serializable {
    private SingletonTest05() {
        if (singletonTest05 != null) {
            // 避免反射去调用私有构造方法破坏单例
            throw new RuntimeException("单例只能实例化一次");
        }
    }

    ;
    private static volatile SingletonTest05 singletonTest05;

    public static SingletonTest05 getInstance() {
        if (singletonTest05 == null) {
            synchronized (SingletonTest05.class) {
                if (singletonTest05 == null) {
                    singletonTest05 = new SingletonTest05();
                }
            }
        }
        return singletonTest05;
    }
    // 防止通过反序列化来破坏单例
    private Object readResolve() {
        return singletonTest05;
    }
}
// 静态内部类的方式

/**
 * 第一次主动使用的是时候，并不会去初始化静态内部类
 * 只有调用内部类的静态方法的时候才会
 */
class SingletonTest06 {
    private SingletonTest06() {
    }

    ;

    //private static SingletonTest06 singletonTest06;
    private static class InnerSingletonTest06 {
        private static final SingletonTest06 instance = new SingletonTest06();
    }

    public static SingletonTest06 getInstance() {
        return InnerSingletonTest06.instance;
    }

    public static void main(String[] args) {
        SingletonTest06 instance = SingletonTest06.getInstance();
        SingletonTest06 instance1 = SingletonTest06.getInstance();
        System.out.println(instance == instance1);
        System.out.println(instance.equals(instance1));
    }
}

//枚举的方式
class SingletonTest07 {
    private SingletonTest07() {
    }

    enum InnerEnum {
        //创建一个枚举对象，此对象天生单例
        INSTANCE;
        private SingletonTest07 singletonTest07;

        InnerEnum() {
            System.out.println(123);
            singletonTest07 = new SingletonTest07();
        }

        public SingletonTest07 getSingletonTest07() {
            return singletonTest07;
        }
    }

    public static SingletonTest07 getInstance() {
        //会调用构造方法

        return InnerEnum.INSTANCE.getSingletonTest07();
    }

    public static void main(String[] args) {
        SingletonTest07 instance = SingletonTest07.getInstance();
        SingletonTest07 instance1 = SingletonTest07.getInstance();
        System.out.println(instance.equals(instance1));
        System.out.println(instance.hashCode());
        System.out.println(instance1.hashCode());
    }
}
// 通过cas的方式实现单例
class SingletonTest08{
    static AtomicReference<SingletonTest08> atomicReference=new AtomicReference<SingletonTest08>();

    private SingletonTest08() {

    }
    public static SingletonTest08 getInstance(){
        for(;;){
            if (atomicReference.get()!=null){
                return atomicReference.get();
            }
            SingletonTest08 singletonTest08=new SingletonTest08();

            if (atomicReference.compareAndSet(null,singletonTest08)){
                singletonTest08=atomicReference.get();
                return singletonTest08;
            }
        }

    }


}
